package system

import (
	"github.com/gookit/color"
	"gorm.io/gorm"
	"seven-admin/app/admin/schemas/req"
	"seven-admin/app/collection/system"
	"seven-admin/core/config"
	"seven-admin/core/response"
	"seven-admin/util"
	"strconv"
	"strings"
)

type AuthTenantPermService interface {
	SelectMenuIdsByTenantId(tenantId uint, auth *req.AuthReq) (menuIds []uint, e error)
	CacheTenantMenusByTenantId(tenantId uint) (e error)
	BatchSaveByMenuIds(tenantId uint, menuIds string, db *gorm.DB, auth *req.AuthReq) (e error)
	BatchDeleteByTenantId(tenantId uint, db *gorm.DB, auth *req.AuthReq) (e error)
	BatchDeleteByMenuId(menuId uint, auth *req.AuthReq) (e error)
}

type authTenantPermService struct {
	db *gorm.DB
}

// SelectMenuIdsByTenantId 根据角色ID获取菜单ID
func (a authTenantPermService) SelectMenuIdsByTenantId(tenantId uint, auth *req.AuthReq) (menuIds []uint, e error) {
	if tenantId == 0 {
		return []uint{}, nil
	}
	var perms []system.AuthTenantPerm
	color.Blueln("SelectMenuIdsByTenantId, tenant_id: ", tenantId, ", menu_ids: ", menuIds)
	if tenantId != auth.SuperTenantId {
		var tenantHasPerms []uint
		err := a.db.Model(&system.AuthTenantPerm{}).Where("tenant_id = ?", tenantId).Pluck("menu_id", &tenantHasPerms).Error
		if e = response.CheckErr(err, "SelectMenuIdsByTenantId Pluck err"); e != nil {
			return []uint{}, e
		}
		err = a.db.Where("tenant_id = ? AND menu_id in (?)", tenantId, tenantHasPerms).Find(&perms).Error
		if e = response.CheckErr(err, "SelectMenuIdsByTenantId Find perms err"); e != nil {
			return []uint{}, e
		}
		for _, perm := range perms {
			menuIds = append(menuIds, perm.MenuId)
		}
	} else {
		color.Blueln("SelectMenuIdsByTenantId, super_tenant_id: ", auth.SuperTenantId)
		a.db.Model(&system.AuthMenu{}).Pluck("id", &menuIds)
	}
	return
}

// CachetenantMenusByTenantId 缓存租户菜单
func (a authTenantPermService) CacheTenantMenusByTenantId(tenantId uint) (e error) {
	var perms []system.AuthTenantPerm
	err := a.db.Where("tenant_id = ?", tenantId).Find(&perms).Error
	if e = response.CheckErr(err, "CachetenantMenusByTenantId Find perms err"); e != nil {
		return
	}
	var menuIds []uint
	for _, perm := range perms {
		menuIds = append(menuIds, perm.MenuId)
	}
	var menus []system.AuthMenu
	err = a.db.Where(
		"is_disable = ? and id in ? and menu_type in ?", 0, menuIds, []string{"C", "A"}).Order(
		"menu_sort asc, id desc").Find(&menus).Error
	if e = response.CheckErr(err, "CachetenantMenusByTenantId Find menus err"); e != nil {
		return
	}
	var menuArray []string
	if len(config.AdminConfig.CommonUri) > 0 {
		menuArray = append(menuArray, config.AdminConfig.CommonUri...)
	}
	for _, menu := range menus {
		if menu.Perms != "" {
			menuArray = append(menuArray, strings.Trim(menu.Perms, ""))
		}
	}
	util.RedisUtil.HSet(config.AdminConfig.BackstageTenantsKey, strconv.FormatUint(uint64(tenantId), 10), strings.Join(menuArray, ","), 0)
	return
}

// BatchSaveByMenuIds 批量写入角色菜单
func (a authTenantPermService) BatchSaveByMenuIds(tenantId uint, menuIds string, db *gorm.DB, auth *req.AuthReq) (e error) {
	if menuIds == "" {
		return
	}
	if db == nil {
		db = a.db
	}
	err := db.Transaction(func(tx *gorm.DB) error {
		var perms []system.AuthTenantPerm
		for _, menuIdStr := range strings.Split(menuIds, ",") {
			menuId, _ := strconv.ParseUint(menuIdStr, 10, 32)
			perms = append(perms, system.AuthTenantPerm{ID: util.ToolsUtil.MakeUuid(), TenantId: tenantId, MenuId: uint(menuId)})
		}
		txErr := tx.Create(&perms).Error
		var te error
		te = response.CheckErr(txErr, "BatchSaveByMenuIds Create in tx err")
		return te
	})
	e = response.CheckErr(err, "BatchSaveByMenuIds Transaction err")
	return
}

// BatchDeleteByTenantId 批量删除角色菜单(根据角色ID)
func (a authTenantPermService) BatchDeleteByTenantId(tenantId uint, db *gorm.DB, auth *req.AuthReq) (e error) {
	if db == nil {
		db = a.db
	}
	err := db.Delete(&system.AuthTenantPerm{}, "tenant_id = ?", tenantId).Error
	e = response.CheckErr(err, "BatchDeleteByTenantId Delete err")
	return
}

// BatchDeleteByMenuId 批量删除角色菜单(根据菜单ID)
func (a authTenantPermService) BatchDeleteByMenuId(menuId uint, auth *req.AuthReq) (e error) {
	err := a.db.Delete(&system.AuthTenantPerm{}, "menu_id = ?", menuId).Error
	e = response.CheckErr(err, "BatchDeleteByMenuId Delete err")
	return
}

func NewAuthTenantPermService(db *gorm.DB) AuthTenantPermService {
	return &authTenantPermService{
		db: db,
	}
}
